package com.lujianfei.filetransfer

import android.util.Log
import java.net.Socket
import java.nio.charset.Charset
import java.util.concurrent.ArrayBlockingQueue
import java.util.concurrent.ThreadPoolExecutor
import java.util.concurrent.TimeUnit


/**
 * Author: lujianfei
 * Date: 2023/10/16 16:44
 * Description: IP扫描器
 */

class IPScanner private constructor() {

    companion object {
        val instance by lazy { IPScanner() }

        const val CORE_POOL_SIZE = 1
        const val MAX_IMUM_POOL_SIZE = 255
    }

    private val executor: ThreadPoolExecutor by lazy {
        ThreadPoolExecutor(
            CORE_POOL_SIZE, MAX_IMUM_POOL_SIZE,
            2000, TimeUnit.MILLISECONDS, ArrayBlockingQueue(
                CORE_POOL_SIZE
            )
        )
    }

    private var runtime: Runtime? = null
    private var running = false
    fun startScan(callback: (String, ScanStatus) -> Unit) {
        val localIpAddress = TcpManager.instance.localIpAddress()
        if (runtime == null) {
            runtime = Runtime.getRuntime()
        }
        running = true

        for (i in 1 until 255) {
            if (!running) {
                break
            }
            executor.execute {
                val prefix =
                    localIpAddress.substring(0, localIpAddress.lastIndexOf(".")) // ip地址前缀
                val currentIp = "$prefix.$i"
                if (currentIp == localIpAddress) {
                    return@execute
                }
                callback.invoke(currentIp, ScanStatus.Searching)
                runCatching {
                    val socket = Socket(currentIp, TcpManager.port)
                    socket.getOutputStream()?.write(localIpAddress.toByteArray(Charset.forName("UTF-8")))
                    callback.invoke(currentIp, ScanStatus.Success)
                    Log.d("IPScanner=", "ping $currentIp")
                }.onFailure {
                    callback.invoke(currentIp, ScanStatus.Failed)
                }
            }
        }
    }

    fun destroy() {
        running = false
        executor.shutdownNow()
    }
}

enum class ScanStatus {
    Searching,
    Failed,
    Success
}